package com.gupaoedu.security.config;

import com.gupaoedu.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;

import javax.sql.DataSource;

/**
 * 让每一个人的职业生涯不留遗憾
 *
 * @author 波波老师【咕泡学院】
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 表示支持spring表达式注解
//@EnableGlobalMethodSecurity(jsr250Enabled = true) // 示支持jsr250-api的注解
//@EnableGlobalMethodSecurity(securedEnabled = true) // 这才是SpringSecurity提供的注解
public class MyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Autowired
    private  BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /*auth.inMemoryAuthentication()
                .withUser("lisi")
                .password("{noop}123")
                .authorities("ADMIN");*/
        auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);
        http.authorizeRequests() // 设置哪些页面可以直接访问，哪些需要验证
            .antMatchers("/login.html","/error.html").permitAll() // 放过
            .antMatchers("/order/order1").hasRole("USER")
            .antMatchers("order/order2").hasRole("CREATE")
            .anyRequest().authenticated() // 剩下的所有的地址都是需要在认证状态下才可以访问
            .and()
                .formLogin()
                .loginPage("/login.html") // 指定指定要的登录页面
                .loginProcessingUrl("/login.do") // 处理认证路径的请求
                .defaultSuccessUrl("/home.html")
                .failureForwardUrl("/error.html")
            .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login.html")
            .and()
                .rememberMe()//开启rememberme功能
                .tokenRepository(persistentTokenRepository())//设置操作表的Repository
                .tokenValiditySeconds(60 * 60 * 24 * 7)//设置记住我的时间为7天
                .userDetailsService(userService)//设置userDetailsService
                //记住我结束
            .and().csrf().disable();

        // 单用户登录，如果有一个登录了，同一个用户在其他地方不能登录
        //http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true);
        http.sessionManagement().maximumSessions(1).expiredSessionStrategy(expiredSessionStrategy());
    }

    /**
       * 持久化token
       * Security中，默认是使用PersistentTokenRepository的子类InMemoryTokenRepositoryImpl，将token放在内存中
       * 如果使用JdbcTokenRepositoryImpl，会创建表persistent_logins，将token持久化到数据库
       */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
//        tokenRepository.setCreateTableOnStartup(true); // 第一次创建表结构 执行后注销掉
        return tokenRepository;
    }

    @Bean
    public SessionInformationExpiredStrategy expiredSessionStrategy() {
        return new SimpleRedirectSessionInformationExpiredStrategy("/logout");
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }


}
